package lynch.map 
{
	import com.greensock.easing.Linear;
	import com.greensock.TweenNano;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	import lynch.Core.config.ration.Core.config.
	import lynch.display.Container;
	import lynch.enum.MapInfoEnum;
	
	/**
	 * the map of the game
	 * @author 小痛
	 */
	public class WorldMap extends Container 
	{
		/** the ratio of mini map divide by world map */
		private static var ratio:Number;
		
		private var currentMapInfo:MapInfoEnum;
		private var mosaic:MosaicMap = new MosaicMap();
		private var miniMap:MiniMap = new MiniMap();
		private var lastX:int;
		private var lastY:int;
		private var tweenNano:TweenNano;
		private var tileFactory:TileFactory;
		private var helpRect:Rectangle;
		
		/**
		 * tile x y
		 */
		private var cacheBounds:Point = new Point(1, 1);
		
		/**
		 * tile x y
		 */
		private var readyRect:Rectangle = new Rectangle();
		
		public function WorldMap() 
		{
			super();
			tweenNano = new TweenNano(this, 0, { ease:Linear.easeNone, onComplete:updateTiles } );
			tweenNano.kill();
			
			tileFactory = new TileFactory();
			tileFactory.mosaicMap = mosaic;
		}
		
		//--------------------initialize--------------------
		public function initializeInfo(mapInfo:MapInfoEnum):void
		{
			currentMapInfo = mapInfo;
			
			//---update ratio---
			ratio = mapInfo.miniMapTexture.width / (Core.config.tileWidth * mapInfo.mapVTiles);
			mosaic.updateInfo(mapInfo.miniMapTexture, ratio, mapInfo.mapVTiles, mapInfo.mapHTiles);
			tileFactory.updateInfo(mapInfo.mapID);
			
			helpRect = new Rectangle(0, 0, 
					-Core.config.tileWidth * mapInfo.mapVTiles + Core.config.stageWidth,
					-Core.config.tileHeight * mapInfo.mapHTiles + Core.config.stageHeight);
			
			//---update texture---
			miniMap.updateInfo(mapInfo.miniMapTexture);
		}
		
		//--------------------convert-----------------------
		public function screenToWorld(px:int, py:int):Point
		{
			return new Point(px - x, py - y);
		}
		
		public function worldToScreen(px:int, py:int):Point
		{
			return new Point(px + x, py + y);
		}
		
		/**
		 * world map x y to tile x y
		 */ 
		public function worldToTile(px:uint, py:uint):Point
		{
			return new Point((px / Core.config.tileWidth) >> 0, (py / Core.config.tileHeight) >> 0);
		}
		
		/**
		 * tile x y to world map x y
		 */
		public function tileToworld(px:uint, py:uint):Point
		{
			return new Point(px * Core.config.tileWidth, py * Core.config.tileHeight);
		}
		
		public function big2MiniMap(px:uint, py:uint):Point
		{
			return new Point(px * ratio, py * ratio);
		}
		
		public function mini2bigMap(px:uint, py:uint):Point
		{
			return new Point(px / ratio, py / ratio);
		}
		
		//--------------------move-------------------------
		/**
		 * 
		 * @param	tx
		 * @param	ty
		 */
		public function flashTo(tx:int, ty:int):void 
		{
			if (tx > helpRect.x) tx = helpRect.x;
			if (tx < helpRect.width) tx = helpRect.width;
			if (ty > helpRect.y) ty = helpRect.y;
			if (ty < helpRect.height) ty = helpRect.height;
			
			var p:Point = worldToTile(tx, ty);
			var wp:Point = worldToTile(Core.config.stageWidth, Core.config.stageHeight);
			var tvn:int = mapVTiles;
			var thn:int = mapHTiles;
			var sx:int = readyRect.x = Math.max(p.x - cacheBounds.x, 0);
			var sy:int = readyRect.y = Math.max(p.y - cacheBounds.y, 0);
			var fx:int = readyRect.width = Math.min(p.x + wp.x + cacheBounds.x, mapVTiles);
			var fy:int = readyRect.height = Math.min(p.y + wp.y + cacheBounds.y, mapHTiles);
			var tw:int = Core.config.tileWidth;
			var th:int = Core.config.tileHeight;
			
			var gt:Function = tileFactory.getTile;
			for (var i:int = sx; i < fx; i++)
			{
				for (var j:int = sy; j < fy; j++) 
				{
					var t:Tile = gt((j * tvn >> 0) + i % thn);
					t.x = i * tw;
					t.y = j * th;
					addChild(t);
				}
			}
			trace(readyRect, numChildren)
			x = tx;
			y = ty;
		}
		
		/**
		 * you'd better not use this function directly
		 * the tiles update after move complete
		 * @param	tx
		 * @param	ty
		 * @param	time
		 */
		public function moveTo(tx:int, ty:int, duration:int):void
		{
			tweenNano.startTime = getTimer() * 0.001;
			tweenNano.duration = duration;
			tweenNano.vars = checkXY(tx, ty);
			tweenNano.init();
		}
		
		protected function checkXY(tx:int, ty:int):Object
		{
			//---limit left---
			if (tx > 0) tx = 0;
			if (ty > 0) ty = 0;
			
			//---limit right---
			if (tx < helpRect.width) tx = helpRect.width;
			if (ty < helpRect.height) tx = helpRect.height;
			
			return { x:tx, y:ty };
		}
		
		//------------------update------------------------
		/**
		 *  
		 */
		private function updateTiles():void
		{
			//getter / setter are too slow
			var x:int = this.x;
			var y:int = this.y;
			
			//limit rect, no Math.min Math.max
			if (x < helpRect.x) x = helpRect.x;
			if (x > helpRect.width) x = helpRect.width;
			if (y < helpRect.y) y = helpRect.y;
			if (y > helpRect.height) y = helpRect.height;
			
			var p:Point = big2MiniMap(x, y);
			miniMap.updateMiniMapPos(p);
			
			var tw:int = Core.config.tileWidth;
			var th:int = Core.config.tileHeight;
			
			//差了多少块地砖
			var rx:Number = (x - lastX) / tw, ry:Number = (y - lastY) / th;
			var tvn:int = mapVTiles;
			var thn:int = mapHTiles;
			
			var star:int, f:int, i:int, id:int, t:Tile;
			
			//向左走,地图向右
			if (rx > readyRect.x)
			{
				star = readyRect.x - rx;
				if (star < 0) star = 0;
				
				f = readyRect.x;
			} else if (rx < readyRect.width)
			{
				star = readyRect.width - rx;
			}
			
			for (i = star; i < f; ++i) 
			{
				var px:int = i * tvn;
				var py:int = i % thn;
				t = tileFactory.getTile(px + py);
				t.x = tw * px;
				t.y = th * py;
			}
			readyRect.x = star;
			
			
			
			lastX = this.x = x;
			lastY = this.y = y;
		}
		
		//-------------------------------
		
		/** return the instance of MiniMap */
		public function getMiniMap():MiniMap 
		{
			return miniMap;
		}
		
		//-------------------------getter / setter---------------------
		/**	get current map id */
		public function get mapID():int { return currentMapInfo.mapID; }
		/**	get the num of tiles in v */
		public function get mapVTiles():int { return currentMapInfo.mapVTiles; }
		/**	get the num of tiles in H*/
		public function get mapHTiles():int { return currentMapInfo.mapHTiles; }
		/**	get current map name */
		public function get mapName():String { return currentMapInfo.mapName; }
		
	}
}